package com.ruoyi.common.utils.uuid;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;

/**
 * @author ruoyi 序列生成类
 */
public class Seq implements IdentifierGenerator {

    // 通用序列类型
    public static final String commSeqType = "COMMON";

    // 上传序列类型
    public static final String uploadSeqType = "UPLOAD";

    // 通用接口序列数
    private static AtomicInteger commSeq = new AtomicInteger(1);

    // 上传接口序列数
    private static AtomicInteger uploadSeq = new AtomicInteger(1);

    // 机器标识
    private static String machineCode = "A";

    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    // 由于JS最多识别16位长度，因此这里控制长度不超过16位，这里控制为16位
    private static int ID_LENGTH = 16;

    /**
     * @Description: 获取16位id
     * @author GSX
     * @date 2022/5/6 17:05
     * @param entity
     * @return Number
     */
    @Override
    public Number nextId(Object entity) {
        //  生成最大4位随技术
        int i2 = ThreadLocalRandom.current().nextInt(9999);
        String timeStr = String.valueOf(System.currentTimeMillis());
        // 取出时间串前面相同的部分
        timeStr = timeStr.substring(5);
        // 递增生成最大9999的递增ID
        if (atomicInteger.get() == 9999) {
            atomicInteger.set(0);
        }
        int i1 = atomicInteger.getAndIncrement();
        String id = timeStr.concat(String.valueOf(i2)).concat(i1+"");
        // 严格控制ID长度，如果过长 从最前面截取
        if (id.length() > ID_LENGTH) {
            // 计算多了多少位
            int surplusLenth = id.length() - ID_LENGTH;
            id = id.substring(surplusLenth);
        }
        return Long.valueOf(id);
    }

    public static void main(String[] args) {
        Seq seq=new Seq();
        seq.nextId(null).longValue();
        final CountDownLatch latch=new CountDownLatch(1000000);
        Set<Long> set=new HashSet<>();
        for(int i=0;i<1000000;i++){
            Thread thread= new Thread(() -> {
                for(int j=0;j<1;j++){
                    Number number = seq.nextId(new Object());
                    long l = number.longValue();
                    boolean add = set.add(l);
                    System.out.println(l);
                    if(!add) {
                        System.out.println("重复"+l);
                    }
                }
                latch.countDown();
            });
            thread.start();
        }

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取通用序列号
     * 
     * @return 序列值
     */
    public static String getId()
    {
        return getId(commSeqType);
    }
    
    /**
     * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
     * 
     * @return 序列值
     */
    public static String getId(String type)
    {
        AtomicInteger atomicInt = commSeq;
        if (uploadSeqType.equals(type))
        {
            atomicInt = uploadSeq;
        }
        return getId(atomicInt, 3);
    }

    /**
     * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
     * 
     * @param atomicInt 序列数
     * @param length 数值长度
     * @return 序列值
     */
    public static String getId(AtomicInteger atomicInt, int length)
    {
        String result = DateUtils.dateTimeNow();
        result += machineCode;
        result += getSeq(atomicInt, length);
        return result;
    }

    /**
     * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
     * 
     * @return 序列值
     */
    private synchronized static String getSeq(AtomicInteger atomicInt, int length)
    {
        // 先取值再+1
        int value = atomicInt.getAndIncrement();

        // 如果更新后值>=10 的 (length)幂次方则重置为1
        int maxSeq = (int) Math.pow(10, length);
        if (atomicInt.get() >= maxSeq)
        {
            atomicInt.set(1);
        }
        // 转字符串，用0左补齐
        return StringUtils.padl(value, length);
    }
}
